/**
 * 
 */
package com.desksoft.ecommerce.util.remoteio.realize;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Vector;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.desksoft.ecommerce.util.remoteio.RemoteIOUtil;
import com.desksoft.utility.exception.RemoteIOException;
import com.desksoft.utility.jsch.JSCHActionHandler;
import com.desksoft.utility.jsch.JSCHTemplate;
import com.desksoft.utility.string.StringUtil;
import com.google.common.io.Files;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;

/***************************************
 * <pre>
 * 版权所有：杭州迪科软件 保留所有权利
 * 创建日期: Apr 27, 2012
 * 创建作者：yejw
 * 文件名称：SFTPRemoteIOUtil.java
 * 版本：1.0
 * 功能：
 * 最后修改时间：Apr 27, 2012
 * 修改记录：
 * </pre>
 *****************************************/
public class SFTPRemoteIOUtil extends RemoteIOUtil {
	
	/**
	 * 
	 */
	protected static final Log log = LogFactory.getLog(SFTPRemoteIOUtil.class);
	
	/**
	 * 
	 */
	protected String rootPath;
	protected JSCHTemplate template = null;

	/* (non-Javadoc)
	 * @see com.desksoft.ecommerce.util.remoteio.RemoteIOUtil#initRemote()
	 */
	@Override
	public void initRemote() {
		this.rootPath = StringUtil.join(this.rootDir, "/");
		this.template = this.getJSCHTemplate();
	}

	/* (non-Javadoc)
	 * @see com.desksoft.ecommerce.util.remoteio.RemoteIOUtil#getInputStream(java.lang.String)
	 */
	@Override
	public InputStream getInputStream(final String path) throws IOException {
		return template.execute(new JSCHActionHandler() {
			
			@SuppressWarnings("unchecked")
			@Override
			public InputStream handler(Channel channel) throws SftpException, JSchException, IOException {
				ChannelSftp sftp = (ChannelSftp) channel;
				return sftp.get(logAct(joinPath(path), "Get InputStream"));
			}
		});
	}
	
	/* (non-Javadoc)
	 * @see com.desksoft.ecommerce.util.remoteio.RemoteIOUtil#getOutputStream(java.lang.String)
	 */
	@Override
	public OutputStream getOutputStream(final String path) throws IOException {
		return template.execute(new JSCHActionHandler() {
			
			@SuppressWarnings("unchecked")
			@Override
			public OutputStream handler(Channel channel) throws SftpException, JSchException, IOException {
				ChannelSftp sftp = (ChannelSftp) channel;
				return sftp.put(logAct(joinPath(path), "Get OutputStream"));
			}
		});
	}

	/* (non-Javadoc)
	 * @see com.desksoft.ecommerce.util.remoteio.RemoteIOUtil#exists(java.lang.String)
	 */
	@Override
	public boolean exists(String path) {
		boolean isExists = true;
		final String joinPath = joinPath(path);
		
		try {
			template.execute(new JSCHActionHandler() {

				@SuppressWarnings("unchecked")
				@Override
				public Object handler(Channel channel) throws SftpException, JSchException, IOException {
					ChannelSftp sftp = (ChannelSftp) channel;
					return sftp.ls(joinPath);
				}
			});
		} catch (RemoteIOException e) {
			if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
				isExists = false;
			} else {
				log.warn(StringUtil.join("SFTP Exists Exception: ", e.id, " -- ", e.getMessage()));
				e.printStackTrace();
			}
		}
		
		logAct(joinPath, "Exists", isExists);
		
		return isExists;
	}

	/* (non-Javadoc)
	 * @see com.desksoft.ecommerce.util.remoteio.RemoteIOUtil#browerDir(java.lang.String)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public String[] browerDir(final String path) throws IOException {
		Vector v = template.execute(new JSCHActionHandler() {

			@SuppressWarnings("unchecked")
			@Override
			public Vector handler(Channel channel) throws SftpException, JSchException, IOException {
				ChannelSftp sftp = (ChannelSftp) channel;
				return sftp.ls(logAct(joinPath(path), "Browser Dir"));
			}
		});
		
		String p = null;
		String[] files = ArrayUtils.EMPTY_STRING_ARRAY;
		Iterator itFiles = v.iterator();
		
		while (itFiles.hasNext()) {
			LsEntry entry = (LsEntry) itFiles.next();
			if (".".equals(entry.getFilename()) || "..".equals(entry.getFilename())) {
				continue;
			}
			
			p = StringUtils.substringAfter(StringUtil.join(joinPath(path), "/", entry.getFilename()), this.rootDir);
			files = (String[]) ArrayUtils.add(files, p);
		}
		
		return files;
	}

	/* (non-Javadoc)
	 * @see com.desksoft.ecommerce.util.remoteio.RemoteIOUtil#mkDir(java.lang.String)
	 */
	@Override
	public String mkDir(final String path) throws IOException {
//		if (exists(path)) {
//			return path;
//		}
		
		this.template.execute(new JSCHActionHandler() {
			
			@SuppressWarnings("unchecked")
			@Override
			public String handler(Channel channel) throws SftpException, JSchException, IOException {
				ChannelSftp sftp = (ChannelSftp) channel;
				String p = joinPath(path);
				sftp.mkdir(logAct(p, "Mkdir"));
				return p;
			}
		});
		
		return null;
	}

	/* (non-Javadoc)
	 * @see com.desksoft.ecommerce.util.remoteio.RemoteIOUtil#delPath(java.lang.String)
	 */
	@Override
	public boolean delPath(final String path) throws IOException {
		if (!exists(path)) {
			return true;
		}
		
		this.template.execute(new JSCHActionHandler() {
			
			@SuppressWarnings("unchecked")
			@Override
			public Boolean handler(Channel channel) throws SftpException, JSchException, IOException {
				ChannelSftp sftp = (ChannelSftp) channel;
				String p = joinPath(path);

				if (StringUtils.isNotBlank(Files.getFileExtension(p))) {
					sftp.rm(logAct(p, "RM"));
				} else {
					sftp.rmdir(logAct(p, "RMDir"));
				}
				
				return true;
			}
		});
		
		return true;
	}
	
	/**
	 * @return
	 */
	private JSCHTemplate getJSCHTemplate() {
//		return new JSCHTemplate("root", this.host, "DeskSoft@***^)(%");
		return new JSCHTemplate(
				this.settings.getUsername(), 
				this.settings.getHost(), 
				this.settings.getPassword(), 
				Integer.parseInt(this.settings.getPort())
			);
	}
	
//	public static void main(String[] args) throws IOException, JSchException, SftpException {
//		RemoteIOUtil remoteIO = new SFTPRemoteIOUtil();
//		remoteIO.setHost("192.168.168.74");
//		remoteIO.setRootDir("/usr/remote/nfs/mall");
//		remoteIO.initRemote();
//		
//		InputStream in = remoteIO.getInputStream("/template/demo/login.xml");
//		FileUtils.copyInputStreamToFile(in, new File("f:/test.txt"));
//		
//		IOUtil.writeToOutputStreamBufferSizeFlush(
//				new ByteArrayInputStream("just test".getBytes()), remoteIO.getOutputStream("/template/demo/test1.txt"));
//		
//		log.debug(remoteIO.exists("template/demo/login.xml"));
//		log.debug(remoteIO.exists("template/demo/nonexistfile.txt"));
//		log.debug(remoteIO.exists("template"));
//		log.debug(remoteIO.exists("template/noneexistdir"));
//		
//		remoteIO.mkDir("template/abcdtxt");
//		log.debug(ArrayUtils.toString(remoteIO.browerDir("template")));
//		remoteIO.delPath("template/abcdtxt");
//		log.debug(ArrayUtils.toString(remoteIO.browerDir("template")));
//		
//		remoteIO.delPath("template/noneexist");
//		remoteIO.delPath("template/demo/test1.txt");
//		
//		remoteIO.disconnect();
//	}

	/* (non-Javadoc)
	 * @see com.desksoft.ecommerce.util.remoteio.RemoteIOUtil#disconnect()
	 */
	@Override
	public void disconnect() {
		this.template.closeSession();
	}
	
	/**
	 * 
	 * @param path
	 * @return
	 */
	private String joinPath(String path) {
		return StringUtils.replace(StringUtil.join(this.rootPath, path), "//", "/");
	}

	/**
	 * 
	 * @param path
	 * @param action
	 * @return
	 */
	private String logAct(String path, String action) {
		return logAct(path, action, null);
	}
	
	/**
	 * 
	 * @param path
	 * @param action
	 * @param result
	 * @return
	 */
	private String logAct(String path, String action, Object result) {
		if (log.isDebugEnabled()) {
			log.debug(StringUtil.join("SFTP ", action, " : ", path, " -- ", (null == result ? StringUtils.EMPTY : result.toString())));
		}
		
		return path;
	}
}
